#include "stdafx.h"
#include "m.h"

#define QUERYINTERFACE "QueryInterface"

extern "C" {
	void * f_new_class_comptr(char *cls,char *p);
	void f_free_class_comptr(void *p);
	long f_get_class_dispid(void *s,char *p);

	svalue_t * getstack();
	control_stack_t *getcontrolstack();

	void f_com_function(char *name,void *p,long id,svalue_t *pr);
	void f_com_put_property(void *iptr,long id,svalue_t *v);
	void f_com_get_property(void *iptr,long id,svalue_t *v);

	void * f_get_com_typelib(char *pInterface,char *pClass);
	int f_check_comfunction_type(void *,char *,unsigned short *);
	int f_check_com_type(void *,char *,unsigned short);
	void f_free_com_typelib(void *);

	DWORD GetIniString(LPCTSTR lpAppName,LPCTSTR lpKeyName,LPCTSTR lpDefault,LPTSTR lpReturnedString,DWORD nSize);
	int GetIniInt(LPCTSTR lpAppName,LPCTSTR lpKeyName,int iDefault);

};

int strncmpi(const char *s1,const char *s2,int len)
{
	char ch1,ch2;
	while((*s1)&&(*s2)&&(len>0)){
		ch1=*s1;
		if((ch1>='A')&&(ch1<='Z'))ch1+=0x20;
		ch2=*s2;
		if((ch2>='A')&&(ch2<='Z'))ch2+=0x20;
		if(ch1!=ch2){
			if(ch1>ch2)
				return 1;
			else
				return -1;
		}
		len--;
	}
	if(len==0)return 0;
	if(*s1)
		return 1;
	else
		return -1;
}

static BOOL ToMudPath(const char *src,char *path,int size)
{
	int len,i;
	char buf[256];
	if(!GetCurrentDirectory(sizeof(buf),buf)){
		return FALSE;
	}
	len=strlen(buf);
	if(strncmpi(buf,src,len))return FALSE;
	if(src[len]!='\\')return FALSE;
	if(!path)return TRUE;
	i=0;
	while(src[len]&&(i<size)){
		if(src[len]=='\\')
			path[i]='/';
		else
			path[i]=src[len];
		len++;
		i++;
	}
	if(i<size)path[i]=0;
	return TRUE;
}

static BOOL FromMudPath(const char *src,char *path,int size)
{
	char *p;
	if(get_current_object()){
		p=check_valid_path((char *)src,get_current_object(),"com",0);
		if(!p)return FALSE;
	} else {
		p=(char *)&src[1];
	}
	if(!GetCurrentDirectory(size,path)){
		return FALSE;
	}
	if(strlen(path)+strlen(p)+1>(unsigned int)size)return FALSE;
	strcat(path,"\\");
	strcat(path,p);
	return TRUE;
}

extern "C" void str_perror (char * s, char * what, char * file, long err);

int ComError(HRESULT ret,LPCTSTR str)
{
	char buf[256];
	if(ret==NOERROR)return 0;
	str_perror(buf,(char *)str,"COM",ret);
	error(buf);
	return 1;
}

IDispatch *GetMudOs();

void call_event(void *iptr,int event)
{
	IDispatch *pd;
	DISPPARAMS param;
	HRESULT ret;
	VARIANTARG Arg;
	DISPID id;
	WORD *p;

	pd=(IDispatch *)iptr;

	if(event==0){
		Arg.vt=VT_DISPATCH;
		Arg.pdispVal=GetMudOs();
		param.rgvarg=&Arg;
		param.cArgs=1;

		if(!Arg.pdispVal)return;
	} 
	else if(event==1){
		param.rgvarg=NULL;
		param.cArgs=0;
	}
	else return;

	param.rgdispidNamedArgs=NULL;
	param.cNamedArgs=0;

	Cc2w c2w;
	if(event==0)c2w.in("OnNewObject");
	if(event==1)c2w.in("OnFreeObject");
	p=c2w.out();

	ret=pd->GetIDsOfNames(IID_NULL,&p,1,LOCALE_SYSTEM_DEFAULT,&id);
	if(ret==S_OK)
		ret=pd->Invoke(id,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD,&param,NULL,NULL,NULL);
	if((event==0)&&(ret!=S_OK)){
		Arg.pdispVal->Release();
	}
}

struct MAP_GUID{
	CLSID clsid;
	IID   iid;
	char  cls[128];
	char  iface[128];
	char  dll[128];
	int   idx;  // type info's index in typelib
};
#define MAX_MAP_GUID 256
static struct MAP_GUID map_guid[MAX_MAP_GUID];
MAP_GUID * map_add(char *cls,char *iface)
{
	int i;
	for(i=0;i<MAX_MAP_GUID;i++)if(map_guid[i].cls[0]){
		if(strcmpi(map_guid[i].cls,cls))continue;
		if(strcmp(map_guid[i].iface,iface))continue;
		return &map_guid[i];
	}
	for(i=0;i<MAX_MAP_GUID;i++)if(!map_guid[i].cls[0]){
		strcpy(map_guid[i].cls,cls);
		strcpy(map_guid[i].iface,iface);
		return &map_guid[i];
	}
	return NULL;
}

MAP_GUID * map_find(char *cls,char *iface)
{
	int i;
	for(i=0;i<MAX_MAP_GUID;i++)if(map_guid[i].cls[0]){
		if(strcmpi(map_guid[i].cls,cls))continue;
		if(strcmp(map_guid[i].iface,iface))continue;
		return &map_guid[i];
	}
	return NULL;
}

MAP_GUID * map_find(REFIID iid)
{
	int i;
	for(i=0;i<MAX_MAP_GUID;i++)if(map_guid[i].cls[0]){
		if(map_guid[i].iid==iid)return &map_guid[i];
	}
	return NULL;
}


void * f_new_class_comptr(char *pInterface,char *pClass)
{
	MAP_GUID * pmap;
	HRESULT    ret;
	void *     pv;

	pmap=map_find(pClass,pInterface);
	if(!pmap){
		ComError(2,"map_find");
		return NULL;
	}
	ret=CoCreateInstance(pmap->clsid,NULL,CLSCTX_INPROC_SERVER,pmap->iid,&pv);
	if(ComError(ret,"CoCreateInstance"))return NULL;

	call_event(pv,0);
	return pv;
}

void f_free_class_comptr(void *p)
{
	IDispatch *pd;
	pd=(IDispatch *)p;
	call_event(p,1);
	pd->Release();
}

long f_get_class_dispid(void *iptr,char *pname)
{
	IDispatch *pd;
	HRESULT ret;
	DISPID id;
	WORD *p;
	pd=(IDispatch *)iptr;

	if(!strcmp(pname,QUERYINTERFACE)){
		return 1;
    } else {
		ITypeInfo *pTypeInfo;
		Cc2w c2w;
		c2w.in(pname);
		p=c2w.out();

		ret=pd->GetTypeInfo(0,LOCALE_SYSTEM_DEFAULT,&pTypeInfo);
		if(ret!=S_OK){
			pTypeInfo->Release();
			ComError(ret,"GetTypeInfo"); // never return
		}
		ret=pTypeInfo->GetIDsOfNames(&p,1,&id);
		pTypeInfo->Release();
	}
	if(ComError(ret,"GetIDsOfNames"))return 0;
	return id;
}


void ConvertArg(svalue_t *sp,VARIANT *v)
{
	if(sp->type==T_NUMBER){
		v->vt=VT_INT;
		v->lVal=sp->u.number;
	}
	if(sp->type==T_STRING){
		Cc2w c2w;
		v->vt=VT_BSTR;
		c2w.in(sp->u.string);
		v->bstrVal=SysAllocString(c2w.out());
	}
	if(sp->type==T_REAL){
		v->vt=VT_R4;
		v->fltVal=sp->u.real;
	}
	if( (sp->type==T_CLASS)||
		(sp->type==T_ARRAY)||
		(sp->type==T_MAPPING)||
		(sp->type==T_OBJECT)){
		CComObject<CMValue> *pv;
		v->vt=VT_DISPATCH;
		pv=new CComObject<CMValue>;
		pv->Create(sp);
		pv->AddRef();
		pv->QueryInterface(IID_IDispatch,(void **)&v->pdispVal);  // self add ref
		pv->Release();
	}
}

void ConvertRet(svalue_t *sp,VARIANT *v,HRESULT *pret)
{
	if(v->vt==VT_INT){
		sp->type=T_NUMBER;
		sp->u.number=v->lVal;
	}
	if(v->vt==VT_I4){
		sp->type=T_NUMBER;
		sp->u.number=v->lVal;
	}
	if(v->vt==VT_R4){
		sp->type=T_REAL;
		sp->u.real=v->fltVal;
	}
	if(v->vt==VT_BSTR){
		Cw2c w2c;
		sp->type=T_STRING;
	    sp->subtype = STRING_MALLOC;
		w2c.in(v->bstrVal);
		sp->u.string = string_copy(w2c.out(), "copy_and_push_string");
		SysFreeString(v->bstrVal);
	}
	if(v->vt==VT_DISPATCH){
		HRESULT ret;
		CComObject<CMValue> *o;
		if(!v->pdispVal)return;
		ret=v->pdispVal->QueryInterface(IID_IMValue,(void **)&o);
		v->pdispVal->Release();
		if(ret!=S_OK){
			*pret=ret;
			return;
		}
		_assign_svalue_no_free(sp,o->GetSValue());
		o->Release();
	}
}




void f_com_function(char *name,void *iptr,long id,svalue_t *pr)
{
	IDispatch *pd;
	DISPPARAMS param;
	VARIANT retv;
	HRESULT ret;
	EXCEPINFO except;
	unsigned int argerror;
	VARIANTARG Args[16];
	int i,n;

	svalue_t *sp=getstack();

	pd=(IDispatch *)iptr;


	if(!strcmp(name,QUERYINTERFACE)){
		// p->QueryInterface("IBbs")
		class_t   * pcls;
		MAP_GUID  * pmap;
		IID         iid;
		TYPEATTR  * ptypeattr;
		IDispatch * pthis;
		ITypeInfo * pinfo,* pnewinfo;
		program_t * current_prog;
		class_def_t cld;
		class_member_entry_t *cme;
		if(sp->type!=T_STRING){
			error("COM: call " QUERYINTERFACE " with NULL string.\n");
		}
		// first, seach the name in class define name
		current_prog=get_current_prog();
		for(i=0;i<current_prog->num_classes;i++){
			if(!current_prog->classes[i].com_name)continue;
			if(!strcmp(sp->u.string,current_prog->strings[current_prog->classes[i].name])){
				break;
			}
		}
		if(i>=current_prog->num_classes){
			error("COM: call " QUERYINTERFACE " with unknown class name.\n");
		}

		ret=pd->GetTypeInfo(0,LOCALE_SYSTEM_DEFAULT,&pinfo);
		if(ComError(ret,"GetTypeInfo"))return;
		pinfo->GetTypeAttr(&ptypeattr);
		// search in my COM table with IID
		iid=ptypeattr->guid;
		pmap=map_find(ptypeattr->guid);
		pinfo->ReleaseTypeAttr(ptypeattr);
		if(!pmap){
			error("COM: internal error 1\n");
		}
		pnewinfo=(ITypeInfo *)f_get_com_typelib(sp->u.string,pmap->cls);
		if(!pnewinfo){
			pinfo->Release();
			error("COM: interface not found in this class.\n");
		}
		pinfo->Release();
		ret=pnewinfo->GetTypeAttr(&ptypeattr);
		if(ComError(ret,"QueryInterface")){
			f_free_com_typelib(pnewinfo);
			return;
		}
		if(iid==ptypeattr->guid){
			pnewinfo->ReleaseTypeAttr(ptypeattr);
			f_free_com_typelib(pnewinfo);
			error("COM: " QUERYINTERFACE " with same interface.\n");
			return;
		}
		iid=ptypeattr->guid;
		pnewinfo->ReleaseTypeAttr(ptypeattr);
		f_free_com_typelib(pnewinfo);

		ret=pd->QueryInterface(iid,(void **)&pthis);
		if(ComError(ret,"QueryInterface"))return;
		
		cld=current_prog->classes[i];
		cld.com_name=0;  // dont call f_new_class_comptr
		pcls=_allocate_class(&cld,0);
		if(!pcls)return;
	    cme = current_prog->class_members + cld.index;
		n = cld.size;
		pcls->com_ptr=pthis;
		while(n--){
			pcls->item[n].type |= T_COM_PROPERTY;
			pcls->item[n].u.comid=f_get_class_dispid(pcls->com_ptr,current_prog->strings[cme[n].name]);
		}
		call_event(pthis,0);
		pr->type = T_CLASS;
		pr->u.cls = pcls;
		return;
	}

	if(getcontrolstack()->num_local_variables>16)error("too many argument(>16)");

	for(i=0;i<getcontrolstack()->num_local_variables;i++){
		ConvertArg(&sp[-i],&Args[i]);
	}

	param.rgvarg=Args;
	param.rgdispidNamedArgs=NULL;
	param.cArgs=getcontrolstack()->num_local_variables;
	param.cNamedArgs=0;

	try {
		ret=pd->Invoke(id,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_METHOD,&param,&retv,&except,&argerror);
	} 
	catch(COleException * e){
		ret=e->m_sc;
	}

	for(i=0;i<getcontrolstack()->num_local_variables;i++){
		if(Args[i].vt==VT_BSTR)SysFreeString(Args[i].bstrVal);
	}
	ConvertRet(pr,&retv,&ret);
	ComError(ret,"CallComFunction");
}

void f_com_put_property(void *iptr,long id,svalue_t *v)
{
	IDispatch *pd;
	DISPPARAMS param;
	HRESULT ret;
	EXCEPINFO except;
	unsigned int argerror;
	VARIANTARG Arg;
	DISPID pid;

	svalue_t *sp=getstack();

	pd=(IDispatch *)iptr;

	ConvertArg(sp,&Arg);

	pid=DISPID_PROPERTYPUT;
	param.rgvarg=&Arg;
	param.rgdispidNamedArgs=&pid;
	param.cArgs=1;
	param.cNamedArgs=1;

	try{
		ret=pd->Invoke(id,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_PROPERTYPUT,&param,NULL,&except,&argerror);
	}
	catch(COleException * e){
		ret=e->m_sc;
	}

	if(ComError(ret,"CallComFunction"))return;
}

void f_com_get_property(void *iptr,long id,svalue_t *v)
{
	IDispatch *pd;
	DISPPARAMS param;
	VARIANT retv;
	HRESULT ret;
	EXCEPINFO except;
	unsigned int argerror;

	svalue_t *sp=getstack();

	pd=(IDispatch *)iptr;


	param.rgvarg=NULL;
	param.rgdispidNamedArgs=NULL;
	param.cArgs=0;
	param.cNamedArgs=0;

	try {
		ret=pd->Invoke(id,IID_NULL,LOCALE_SYSTEM_DEFAULT,DISPATCH_PROPERTYGET,&param,&retv,&except,&argerror);
	}
	catch(COleException * e){
		ret=e->m_sc;
	}

	ConvertRet(v,&retv,&ret);

	if(ComError(ret,"CallComFunction"))return;
}


void * f_get_com_typelib(char *pInterface,char *pClass)
{
	int         count;
	char        dll[128];
	char        buf[256];
	BSTR        bstrName;
	LONG        size;
	ITypeLib  * itype;
    ITypeInfo * pti,*pret;
    TYPEATTR*   pattr;
	HRESULT     ret;
	Cc2w        c2w;
	Cw2c        w2c;
	MAP_GUID *  p;

	p=map_find(pClass,pInterface);
	if(!p){
		if(pClass[0]!='/'){
			char   clsidstr[256];
			if(pClass[0]!='{'){
				sprintf(buf,"%s\\CLSID",pClass);
				size=sizeof(clsidstr);
				if(RegQueryValue(HKEY_CLASSES_ROOT,buf,clsidstr,&size)!=ERROR_SUCCESS){
					return NULL;
				}
			} else
				strcpy(clsidstr,pClass);
			sprintf(buf,"CLSID\\%s\\InprocServer32",clsidstr);
			size=sizeof(dll);
			if(RegQueryValue(HKEY_CLASSES_ROOT,buf,dll,&size)!=ERROR_SUCCESS){
				return NULL;
			}
			if(!ToMudPath(dll,NULL,0)){
				GetIniString("com",pClass,"",dll,128);
				if(!dll[0])return NULL;
			}
		} else {
			if(!FromMudPath(pClass,dll,sizeof(dll)))return NULL;
		}
		c2w.in(dll);
	} else {
		c2w.in(p->dll);
	}
	if(LoadTypeLib(c2w.out(),&itype)!=S_OK)return NULL;

	if(p){
		ret = itype->GetTypeInfo( p->idx, &pti );
		if(ret!=S_OK)return NULL;
		itype->Release();
		return pti;
	} else {
		count=0;
		UINT uiInfos = itype->GetTypeInfoCount() ;
		for(int i=0;i<(int)uiInfos;i++){
			ret = itype->GetTypeInfo( i, &pti );
			if(ret!=S_OK)continue;
			ret = pti->GetTypeAttr( &pattr );
			if(ret!=S_OK){
				pti->Release() ;
				continue;
			}
			ret=pti->GetDocumentation( MEMBERID_NIL, &bstrName, NULL, NULL, NULL );
			if(ret!=S_OK){
				pti->ReleaseTypeAttr( pattr ) ;
				pti->Release() ;
				continue;
			}
			if(pattr->typekind==TKIND_DISPATCH){
				w2c.in(bstrName);
				if(strcmp(pInterface,w2c.out())){
					pti->ReleaseTypeAttr( pattr );
					pti->Release() ;
					continue;
				}
				if(!p)p=map_add(pClass,pInterface);
				if(p){
					strcpy(p->dll,dll);
					p->iid=pattr->guid;
					p->idx=i;
					pret=pti;
					pti->ReleaseTypeAttr( pattr );
					count++;
					if(count>=2)goto getit;
					continue;
				}
			}
			if(pattr->typekind=TKIND_COCLASS){
				ITypeInfo* ptiImpl = NULL ;
				HREFTYPE   href = NULL ;
				TYPEATTR*  pattrImpl = NULL ;
				BSTR       bstrName = NULL ;
				for (UINT n = 0 ; n < pattr->cImplTypes ; n++){
					if(pti->GetRefTypeOfImplType(n, &href)!=S_OK)continue;
					if(pti->GetRefTypeInfo( href, &ptiImpl )!=S_OK)continue;
					if(ptiImpl->GetTypeAttr( &pattrImpl)!=S_OK)continue;
					if (pattrImpl->typekind == TKIND_DISPATCH){
						ptiImpl->GetDocumentation( MEMBERID_NIL, &bstrName, NULL,NULL,NULL);
						w2c.in(bstrName);
						if(!strcmp(pInterface,w2c.out())){
							if(!p)p=map_add(pClass,pInterface);
							if(p){
								p->clsid=pattr->guid;
								count++;
							}
						}
						SysFreeString( bstrName ) ;
					}
					ptiImpl->ReleaseTypeAttr( pattrImpl ) ;
					ptiImpl->Release() ;
				}
			}
			pti->ReleaseTypeAttr( pattr );
			pti->Release();
			if(count>=2)goto getit;
		}
	}
	itype->Release();
	return NULL;

	// if the dll is not register,register it
getit:
	itype->Release();
	ret=StringFromCLSID(p->clsid,&bstrName);
	if(ret!=S_OK)return NULL;
	w2c.in(bstrName);
	CoTaskMemFree(bstrName);
	sprintf(buf,"CLSID\\%s\\InprocServer32",w2c.out());
	size=sizeof(dll);
	if(RegQueryValue(HKEY_CLASSES_ROOT,buf,dll,&size)!=ERROR_SUCCESS){
		typedef HRESULT (WINAPI *FDllRegisterServer)(void);
		FDllRegisterServer DllRegisterServer;
		HINSTANCE hm;
		c2w.in(dll);
		hm=CoLoadLibrary(c2w.out(),TRUE);
		if(hm){
			DllRegisterServer=(FDllRegisterServer)GetProcAddress(hm,"DllRegisterServer");
			if(DllRegisterServer)DllRegisterServer();
			CoFreeLibrary(hm);
		}
	}
	return pret;
}

#include "../compiler.h"
// in compile time
VARTYPE FromLpcType(unsigned short type)
{
	if(type==TYPE_NUMBER) return VT_INT;
	if(type==TYPE_STRING) return VT_BSTR;
	if(type==TYPE_REAL)   return VT_R4;
	if(type==TYPE_VOID)   return VT_VOID;
	if(type==TYPE_OBJECT) return VT_DISPATCH;
	if(type==TYPE_MAPPING)return VT_DISPATCH;
	if((type&TYPE_MOD_ARRAY)==TYPE_MOD_ARRAY) return VT_DISPATCH;
	if((type&TYPE_MOD_CLASS)==TYPE_MOD_CLASS) return VT_DISPATCH;
	return VT_NULL;
}

// in compile time
int TypeCompatible(VARTYPE vt,unsigned short type)
{
	return vt==FromLpcType(type);
}


static int i_check_comfunction_type(void *iptr,char *name,unsigned short *ptype,int isfunc)
{
	ITypeInfo FAR* itype;
    TYPEATTR*      pattr;
    FUNCDESC*      pfuncdesc;
	HRESULT        ret;
    BSTR           bstrName;
	int            funcret;
	Cw2c           w2c;
	
	if(!strcmp(name,QUERYINTERFACE)){
		int i=0;
		while(ptype[i])i++;
		if( (i==2)&&
			(ptype[1]==TYPE_STRING)&&
			((ptype[0]&TYPE_MOD_CLASS)==TYPE_MOD_CLASS))
		{
			return 0;
		}
		return 2;
	}

	if(!iptr)return 0;
	itype=(ITypeInfo *)iptr;

	ret = itype->GetTypeAttr( &pattr );
	if(ret!=S_OK)return 0;
	funcret=1;
    for (int n = 0 ; n < pattr->cFuncs ; n++)if(funcret==1){
		int i;
		ret = itype->GetFuncDesc( n, &pfuncdesc );
		if(ret!=S_OK)continue;

		if(isfunc){
			if (pfuncdesc->invkind & INVOKE_PROPERTYGET){
				continue;
			}
			if (pfuncdesc->invkind & INVOKE_PROPERTYPUT){
				continue;
			}
		} else {
			// only check INVOKE_PROPERTYGET
			if ((pfuncdesc->invkind & INVOKE_PROPERTYGET)==0)continue;
		}

		ret=itype->GetDocumentation( pfuncdesc->memid, &bstrName, NULL, NULL, NULL );
		if(ret!=S_OK){
	        itype->ReleaseFuncDesc( pfuncdesc ) ;
			continue;
		}
		w2c.in(bstrName);
		SysFreeString(bstrName);
		if(strcmp(name,w2c.out())){
	        itype->ReleaseFuncDesc( pfuncdesc ) ;
			continue;
		}
		i=0;
		while(ptype[i])i++;

		if(FromLpcType(ptype[0])==VT_NULL)i=-1;

		if(TypeCompatible(pfuncdesc->elemdescFunc.tdesc.vt,ptype[0]))i--;

		if(isfunc){
			for ( int n = 0 ; n < pfuncdesc->cParams ; n++ )if(ptype[n+1]){
				if(TypeCompatible(pfuncdesc->lprgelemdescParam[n].tdesc.vt,ptype[n+1]))i--;
			} else 
				i--;
		}
		itype->ReleaseFuncDesc( pfuncdesc ) ;
		if(i!=0)funcret=2;else funcret=0;
	}
    itype->ReleaseTypeAttr( pattr ) ;
	return funcret;
}


int f_check_comfunction_type(void *iptr,char *name,unsigned short *ptype)
{
	return i_check_comfunction_type(iptr,name,ptype,1);
}
int f_check_com_type(void *iptr,char * name,unsigned short type)
{
	ITypeInfo   FAR* itype;
    VARDESC*    pvardesc;
	HRESULT     ret;
    TYPEATTR*   pattr;
	int         varret;
    BSTR        bstrName;
	Cw2c        w2c;

	if(!iptr)return 0;
	itype=(ITypeInfo *)iptr;
	ret = itype->GetTypeAttr( &pattr );
	if(ret!=S_OK)return 0;

	varret=1;
    for (int n = 0 ; n < pattr->cVars ; n++)if(varret==1){
		ret=itype->GetVarDesc( n, &pvardesc );
		if(ret!=S_OK)continue;
		ret=itype->GetDocumentation( pvardesc->memid, &bstrName, NULL,NULL,NULL);

		w2c.in(bstrName);
		SysFreeString(bstrName);
		if(strcmp(name,w2c.out())){
			itype->ReleaseVarDesc( pvardesc ) ;
			continue;
		}
		varret=2;
		if(TypeCompatible(pvardesc->elemdescVar.tdesc.vt,type))varret=0;
		itype->ReleaseVarDesc( pvardesc ) ;
	}
    itype->ReleaseTypeAttr( pattr ) ;
	if(varret==1){
		unsigned short ptype[2];
		ptype[0]=type;
		ptype[1]=0;
		return i_check_comfunction_type(iptr,name,ptype,0);
	}
	return varret;
}

void f_free_com_typelib(void *iptr)
{
	ITypeInfo FAR* itype;
	if(!iptr)return;
	itype=(ITypeInfo *)iptr;
	itype->Release();
}

